; void crear_arbol_huffman ( nodo_lista_t **l, nodo_arbol_t **a )
%include "macros.mac"
%include "lista_obtener_primero.asm"
%include "lista_insertar_ordenado.asm"
;~extern lista_obtener_primero
;~extern lista_insertar_ordenado
extern free
extern malloc
extern printf

%define ptr_ptr_l [ebp+8]
%define ptr_ptr_a [ebp+12]

%define primero_en_apariciones [ebp-4]	;variable local 1
%define segundo_en_apariciones [ebp-8]	;variable local 2

%define offset_nl_nodo_arbol	0  ; 4bytes
%define offset_nl_sig		4  ; 4bytes

%define sizeof_nodo_lista	8

%define offset_na_simbolo	0  ; 1byte
%define offset_na_apariciones 	1  ; 4bytes
%define offset_na_valido	5  ; 4bytes
%define offset_na_padre		9  ; 4bytes
%define offset_na_izq		13 ; 4bytes
%define offset_na_der		17 ; 4bytes

%define sizeof_nodo_arbol	21


%macro ObtenerApariciones 1
	mov %1, [%1 + offset_na_apariciones]
%endmacro

%macro MarcarNoValido 1
	mov [%1 + offset_na_valido], dword 0
%endmacro

global crear_arbol_huffman




section .text

crear_arbol_huffman:
		convencion_C 8
		push ecx
		push edx

		; nodo_lista* primero_en_apariciones = 	NULL
		mov primero_en_apariciones, dword 0	

		; nodo_lista* segundo_en_apariciones = 	NULL
		mov segundo_en_apariciones, dword 0	

		; ecx = l
		;~mov ecx, ptr_ptr_l

.ciclo:		
		; consigo &primero_en_apariciones, que es de tipo nodo_lista**
		lea ebx, primero_en_apariciones

		; obtengo el primero de la lista		
		push ebx
		push dword ptr_ptr_l
		call lista_obtener_primero
		add esp, 8


		; si habia un solo elemento, la lista quedo vacia
;!! revisar
		mov ecx,ptr_ptr_l
		cmp [ecx], dword 0		; ¿ *l == NULL ?
		jne .casoListaNoVacia
			
		; CASO  *l == NULL
		; devuelvo en *a el arbol de huffman armado
			mov esi, primero_en_apariciones
			
			mov esi, [esi + offset_nl_nodo_arbol]	; esi = primero_en_apariciones->nodo_arbol
			mov edi, ptr_ptr_a			; edi = a
			mov [edi], esi				; *a = ptr a arbol de huffman
		; Libero memoria del ultimo nodo lista
			push dword primero_en_apariciones
			call free
			add esp, 4
			
			jmp .fin

		; CASO  *l != NULL
.casoListaNoVacia:
		; si habia al menos dos elementos
		; Puedo extraer el primero, una vez mas
		lea edx, segundo_en_apariciones

		push edx
		push dword ptr_ptr_l
		call lista_obtener_primero		; obtengo el primero una vez mas
		add esp, 8
		

		; reservo memoria para un nuevo nodo arbol
		push dword sizeof_nodo_arbol
		call malloc
		add esp, 4
		; eax = ptr a nueva_raiz

		; el padre de este nodo es NULL
		mov [eax + offset_na_padre], dword 0
		
		; lo enlazo a sus nuevos hijos (los que estan en primer y segundo nodo lista)
		mov esi, primero_en_apariciones			; primero_en_apariciones es ptr nodo_lista_t
		;~mov esi,[esi]
		mov esi, [esi + offset_nl_nodo_arbol]	; esi = primero_en_apariciones->nodo_arbol
		mov [eax + offset_na_izq], esi		; nueva_raiz->izq = raiz del primer arbol
	
		mov edi, segundo_en_apariciones			; segundo_en_apariciones es ptr nodo_lista_t
		;~mov edi,[edi]
		mov edi, [edi + offset_nl_nodo_arbol]	; edi = segundo_en_apariciones->nodo_arbol
		mov [eax + offset_na_der], edi		; nueva_raiz->der = raiz del segundo arbol
		

		; Enlazo a los hijos con su padre (eax)
		; esi = ptr arbol_izq    edi = ptr arbol_der
		mov [esi + offset_na_padre], eax	;  arbol_izq->padre = eax

		mov [edi + offset_na_padre], eax	;  arbol_der->padre = eax

		; Defino las apariciones del padre como suma de las apariciones de los hijos
		; Despues de eso no opero mas con arbol_izq e  arbol_der. Puedo usar esi y edi
		ObtenerApariciones esi			; esi = arbol_izq->apariciones
		ObtenerApariciones edi			; edi = arbol_der->apariciones
		add esi, edi				; sumo

		mov [eax + offset_na_apariciones], esi	; lo asigno a las apariciones del padre

		; Marco el nodo como no valido, porque no es una hoja
		MarcarNoValido eax

		; salvaguardo el nuevo arbol
		mov esi, eax

		; Reservo memoria para nuevo_nodo_lista
		push dword sizeof_nodo_lista
		call malloc
		add esp, 4

		; eax = ptr a nuevo_nodo_lista
		; esi = ptr a nuevo arbol
		; Le asigno el nuevo arbol
		mov [eax + offset_nl_nodo_arbol], esi

		; Su siguiente es NULL
		mov [eax + offset_nl_sig], dword 0

		; Por ultimo lo inserto ordenado
		push eax		; eax = ptr nuevo_nodo_lista
		push dword ptr_ptr_l		; ecx = l
		call lista_insertar_ordenado
		add esp, 8
		
		; libero los nodos lista que extraje (a los que le saque su arbol)
		push dword primero_en_apariciones
		call free
		add esp, 4

		push dword segundo_en_apariciones
		call free
		add esp, 4
				



		
		jmp .ciclo
		
.fin:
		pop edx
		pop ecx
		convencion_C_fin 8
		
		ret
